import http.*
import korlibs.image.color.*
import korlibs.image.font.*
import korlibs.image.text.*
import korlibs.io.async.*
import korlibs.io.file.std.*
import korlibs.io.net.http.*
import korlibs.korge.input.*
import korlibs.korge.scene.*
import korlibs.korge.service.storage.*
import korlibs.korge.ui.*
import korlibs.korge.view.*
import korlibs.korge.view.align.*
import korlibs.math.geom.*

class HouseScene(private val house: String) : Scene() {

    private val points = ObservableProperty("0")

    override suspend fun SContainer.sceneMain() {
        val font = resourcesVfs["font.ttf"].readTtfFont()
        val textColor = Colors.GOLD
        val textAlignment = TextAlignment.MIDDLE_CENTER

        val inputSize = Size(views.virtualWidth, views.virtualHeight / 5)
        val actionsSize = Size(views.virtualWidth, views.virtualHeight / 5)
        val padSize = Size(views.virtualWidth, views.virtualHeight - inputSize.height - actionsSize.height)

        val input = input(textColor, font, inputSize)

        uiGridFill(
            cols = 3,
            rows = 4,
            spacing = Spacing(10),
            size = padSize
        ) {
            for (i in 9 downTo 1) {
                numberButton(i, font, textColor, textAlignment)
            }
            negateButton(textColor, font, textAlignment)
            zeroButton(font, textColor, textAlignment)
            backspaceButton(textColor, textAlignment)
        }.alignTopToBottomOf(input, 10)

        uiHorizontalFill(
            size = actionsSize,
            padding = 10
        ) {
            backButton(font, textColor, textAlignment)
            sendButton(font, textColor, textAlignment)
        }.alignBottomToBottomOf(this, 5)
    }

    private fun SContainer.input(
        textColor: RGBA,
        font: TtfFont,
        size: Size,
    ): SolidRect {
        val input = solidRect(size, Colors.BLACK)
        text(points.value, input.height / 2, color = textColor, font = font) {
            setTextBounds(Rectangle(input.x, input.y, input.width - 5, input.height - 5))
            alignment = TextAlignment.BASELINE_CENTER
            centerXOn(input)
            points.observe {
                text = it
            }
        }
            .alignTopToTopOf(input, input.height / 2 + 15)
        return input
    }

    private fun UIGridFill.numberButton(
        i: Int,
        font: TtfFont,
        textColor: RGBA,
        textAlignment: TextAlignment
    ) {
        uiButton("") {
            textView.text(
                "$i",
                font = font,
                textSize = this.height - 5,
                color = textColor,
                alignment = textAlignment
            ).position(this.width / 2, this.height / 2)
        }.apply {
            background.apply { colorMul = Colors.BLACK }
        }.onClick { updatePoints(i) }
    }

    private fun UIGridFill.backspaceButton(
        textColor: RGBA,
        textAlignment: TextAlignment
    ) {
        uiButton("") {
            textView.text(
                "<",
                textSize = this.height - 5,
                color = textColor,
                alignment = textAlignment
            ).position(this.width / 2, (this.height / 2) + 5)
        }.apply { background.apply { colorMul = Colors.BLACK } }
            .onClick { backspace() }
    }

    private fun UIGridFill.zeroButton(
        font: TtfFont,
        textColor: RGBA,
        textAlignment: TextAlignment
    ) {
        uiButton("") {
            textView.text(
                "0",
                font = font,
                textSize = this.height - 5,
                color = textColor,
                alignment = textAlignment
            ).position(this.width / 2, this.height / 2)
        }.apply {
            background.apply { colorMul = Colors.BLACK }
        }.onClick { updatePoints(0) }
    }

    private fun UIGridFill.negateButton(
        textColor: RGBA,
        font: TtfFont,
        textAlignment: TextAlignment
    ) {
        uiButton("") {
            this.text(
                "-",
                color = textColor,
                font = font,
                textSize = this.height - 5,
                alignment = textAlignment
            ).position(this.pos.x + this.width / 2, this.height / 2)
        }.apply {
            background.apply { colorMul = Colors.BLACK }
        }.onClick { negate() }
    }

    private fun UIHorizontalFill.backButton(
        font: TtfFont,
        textColor: RGBA,
        textAlignment: TextAlignment
    ) {
        uiButton("") {
            textView.text(
                "Back",
                font = font,
                textSize = this.height / 2,
                color = textColor,
                alignment = textAlignment
            )
                .position(this.width / 4, this.height / 2)
        }.apply {
            background.apply { colorMul = Colors.BLACK }
        }.onClick { sceneContainer.changeTo { HousesScene() } }
    }

    private fun UIHorizontalFill.sendButton(
        font: TtfFont,
        textColor: RGBA,
        textAlignment: TextAlignment
    ) {
        uiButton("") {
            textView.text(
                "Send",
                font = font,
                textSize = this.height / 2,
                color = textColor,
                alignment = textAlignment
            )
                .position(this.width / 2, this.height / 2)
        }.apply {
            background.apply { colorMul = Colors.BLACK }
        }.onClick {
            try {
                PointsHttpClient(storage["serverIp"], storage["id"]).addPoints(house, points.value.toInt())
            } catch (e: Http.HttpException) {
                savePoints(house, points.value.toInt())
            }
            sceneContainer.changeTo { HousesScene() }
        }
    }

    private fun updatePoints(value: Int) {
        points.update(points.value.plus(value.toString()).trimStart('0'))
    }

    private fun negate() {
        val value: String = when (points.value.firstOrNull()) {
            '-' -> points.value.trimStart('0', '-')
            else -> "-${points.value}"
        }
        points.update(value)
    }

    private fun backspace() {
        if (points.value != "-") points.update(points.value.dropLast(1).trimStart('0'))
    }

    private fun savePoints(house: String, points: Int) {
        val pointsToStore = storage.getOrNull(house)?.let { it.toInt() + points } ?: points
        storage[house] = pointsToStore.toString()
    }
}
